package com.labbit.platform.commons.utils.joda;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.springframework.util.CollectionUtils;

import java.sql.Date;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;


/**
 * @Description 时间工具类
 * @Date 2019-07-28 20:01
 * @Author CHEN YU
 **/
@Slf4j
public class JodaUtil {

    /**
     * 一小时毫秒数
     */
    public static final long ONE_HOUR = 1000 * 60 * 60 * 1;

    /**
     * 一天毫秒数
     */
    public static final long ONE_DAY = 24 * ONE_HOUR;

    /**
     * 日期分隔符
     */
    private static final String DATE_SEPARATOR = "\\D+";

    /**
     * 日期格式长度
     */
    private static final int DATE_MAX_LENGTH = 10;

    /**
     * 日期格式长度
     */
    private static final int DATE_LENGTH = 8;

    /**
     * 年月格式长度
     */
    private static final int YEARE_LENGTH = 4;

    /**
     * 日期格式
     */
    public static final String DATE_PATTERN = "yyyyMMdd";

    /**
     * 默认日期时间格式
     */
    public static final String DEFAULT_DATE_TIME = "yyyy-MM-dd HH:mm:ss";

    /**
     * 默认时间格式
     */
    public static final String DEFAULT_TIME = "HH:mm:ss";

    /**
     * 默认日期格式
     */
    public static final String DEFAULT_DATE = "yyyy-MM-dd";

    /**
     * 日期时间格式
     */
    public static final String DATE_TIME_PATTERN = "yyyyMMddHHmmss";

    /**
     * 不从日期字符串转换的格式
     */
    private static String[] noParsePatterns = {"yyyyMMdd", "yyyyMMddHHmmss", "yyyyMMddHHmmssSSS", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm:ss:SSS"
            , "HHmmss", "HH:mm:ss"};

    /**
     * 日期字符串转换支持的日期格式
     */
    private static String[] hasParsePatterns = {
            "yyyy-MM-dd", "yyyy/MM/dd", "yyyy.MM.dd", "yyyy年MM月dd日", "yyyy/MM/dd日",
            "MM-dd-yyyy", "MM/dd/yyyy", "MM.dd.yyyy", "MM月dd日yyyy年", "yyyy年MM月",
    };

    /**
     * DateTimeFormatter 缓存
     */
    private static Map<String, DateTimeFormatter> cache;

    /**
     * 获取日期格式化缓存
     */
    private static Map<String, DateTimeFormatter> getCache() {

        if (!CollectionUtils.isEmpty(cache)) {
            return cache;
        }
        cache = new HashMap<>(noParsePatterns.length + hasParsePatterns.length);
        listDateTimeFormatter(cache, noParsePatterns);
        listDateTimeFormatter(cache, hasParsePatterns);
        return cache;
    }


    /**
     * 获取格式的DateTimeFormatter
     */
    private static void listDateTimeFormatter(Map<String, DateTimeFormatter> map, String[] parsePatterns) {

        for (String parsePattern : parsePatterns) {
            map.put(parsePattern, DateTimeFormat.forPattern(parsePattern));
        }
    }

    /**
     * 获取当前的Timestamp
     */
    public static Timestamp getCurrentTimestamp() {
        return new Timestamp(DateTime.now().getMillis());
    }

    /**
     * 获取当前时间的毫秒数
     *
     * @return 当前的milliseconds
     */
    public static long getCurrentTime() {
        return DateTime.now().getMillis();
    }


    /**
     * 转换日期字符串为DateTime
     */
    public static DateTime parseDatetime(String dateStr) {
        return parseDateTime(dateStr);
    }

    /**
     * 转换为Timestamp
     */
    public static Timestamp parseTimestamp(String dateTimeStr) {

        if (StringUtils.isBlank(dateTimeStr)) {
            return null;
        }

        // 去掉所有的字符
        String timeStr = dateTimeStr.replaceAll(DATE_SEPARATOR, StringUtils.EMPTY);

        DateTime dateTime = parseDateTime(timeStr, noParsePatterns);
        if (dateTime == null) {
            dateTime = parseDateTime(dateTimeStr, hasParsePatterns);
        }

        if (null == dateTime) {
            return null;
        }
        return new Timestamp(dateTime.getMillis());
    }


    /**
     * 输出默认日期时间格式
     */
    public static String printDateTime(Long date) {

        if (null == date) {
            return null;
        }
        return print(date, DEFAULT_DATE_TIME);
    }

    /**
     * 输出默认时间格式
     */
    public static String printTime(Long date) {

        if (null == date) {
            return null;
        }
        return print(date, DEFAULT_TIME);
    }

    /**
     * 输出默认日期时间格式
     */
    public static String printDateTime(Timestamp date) {
        if (date == null) {
            return StringUtils.EMPTY;
        }
        return print(date.getTime(), DEFAULT_DATE_TIME);
    }

    /**
     * 输出日期格式
     */
    public static String printDate(Long sqlDate) {

        if (null == sqlDate) {
            return null;
        }
        return print(sqlDate, DEFAULT_DATE);
    }


    /**
     * 输出日期格式
     */
    public static String printDate(Date sqlDate) {
        return print(sqlDate, DEFAULT_DATE);
    }

    /**
     * 输出指定格式的日期
     */
    public static String print(Date date, String parsePattern) {

        if (null == date) {
            return null;
        }
        return print(date.getTime(), parsePattern);
    }


    /**
     * 转换各类日期字符串为DateTime 日期对象
     *
     * @param dateStr 各类日期字符串
     * @return DateTime 日期
     */
    public static DateTime parseDateTime(String dateStr) {

        // 日期字符串为空
        if (StringUtils.isBlank(dateStr) || YEARE_LENGTH > dateStr.length()) {
            return null;
        }
        if (DATE_MAX_LENGTH < dateStr.length()) {
            dateStr = dateStr.substring(0, DATE_MAX_LENGTH);
        }
        // 去掉所有的字符
        String tempDate = dateStr.replaceAll(DATE_SEPARATOR, StringUtils.EMPTY);
        // 日期格式
        if (DATE_LENGTH == tempDate.length()) {
            return parseDateTime(tempDate, DATE_PATTERN);
        }
        // 其他通用格式
        return parseDateTime(dateStr, hasParsePatterns);
    }

    /**
     * 将各种日期字符串转换为Date 类型
     *
     * @param dateStr 各类日期字符串
     * @return Date类型
     */
    public static Date parseDate(String dateStr) {

        if (StringUtils.isBlank(dateStr)) {
            return null;
        }
        DateTime dateTime = parseDateTime(dateStr);
        if (null == dateTime) {
            return null;
        }
        return new Date(dateTime.getMillis());
    }

    /**
     * 获取时间段相隔天数
     *
     * @param dateStart 开始时间
     * @param dateEnd   结束时间
     * @return 开始到结束时间的天数
     */
    public static int getDaysBetween(DateTime dateStart, DateTime dateEnd) {
        return Days.daysBetween(dateStart, dateEnd).getDays();
    }

    /**
     * 获取指日期加days天
     */
    public static Date plusDaysAndGetDate(String dateTimeStr, int days) {
        try {
            DateTime dateTime = parseDatetime(dateTimeStr);
            if (null == dateTime) {
                return null;
            }
            return plusDaysAndGetDate(dateTime, days);
        } catch (UnsupportedOperationException | IllegalArgumentException e) {
            log.error("can't not parse {} to DateTime", dateTimeStr, e);
            return null;
        }
    }

    /**
     * 获取指日期加days天
     */
    public static Date plusDaysAndGetDate(Date date, int days) {
        try {
            DateTime dateTime = new DateTime(date);
            if (null == dateTime) {
                return null;
            }
            return plusDaysAndGetDate(dateTime, days);
        } catch (UnsupportedOperationException | IllegalArgumentException e) {
            log.error("can't not parse {} to DateTime", date, e);
            return null;
        }
    }

    /**
     * 获取指日期加days天
     */
    public static Date plusDaysAndGetDate(DateTime dateTime, int days) {
        return new Date(dateTime.plusDays(days).getMillis());
    }

    /**
     * 指定时间加hours分钟
     *
     * @param time    当前时间
     * @param minutes 加减的分钟
     * @return
     */
    public static Timestamp plusHoursAndGetDate(DateTime time, int minutes) {

        DateTime dateTime = time.plusMinutes(minutes);
        return new Timestamp(dateTime.getMillis());
    }

    /**
     * 获取当前日期时间字符串
     */
    public static String printCurrentDateTime() {
        return printDateTime(DateTime.now().getMillis());
    }


    /**
     * 根据指定格式转换
     */
    private static DateTime parseDateTime(String dateStr, String... parsePatterns) {

        for (String parsePattern : parsePatterns) {
            DateTime dateTime = parseDateTime(getCache().get(parsePattern), dateStr);
            if (null != dateTime) {
                return dateTime;
            }
        }
        return null;
    }

    /**
     * 转换日期
     */
    public static DateTime parseDateTime(DateTimeFormatter formatter, String dateStr) {

        DateTime dateTime = null;
        try {
            dateTime = formatter.parseDateTime(dateStr);
        } catch (IllegalArgumentException e) {
            log.warn(String.format("转换日期[%s]失败", dateStr));
        }
        return dateTime;
    }

    /**
     * 输出指定格式的日期
     */
    public static String print(long date, String parsePattern) {

        DateTimeFormatter dateTimeFormatter = getCache().get(parsePattern);
        if (null == dateTimeFormatter) {
            return null;
        }
        return dateTimeFormatter.print(date);
    }

    /**
     * 获取当前时间
     *
     * @return 当前时间
     */
    public static Date getNowDate() {
        return new Date(getCurrentTime());
    }

    /**
     * 根据天数转换为日期
     */
    public static Date getDate(String value) {

        if (StringUtils.isBlank(value)) {
            return null;
        }
        try {
            Long days = Long.parseLong(value);
            return new Date((days - 25569L) * 86400L * 1000L);
        } catch (NumberFormatException e) {
            return null;
        }
    }


    /**
     *
     * @param date
     * @return
     */
    public static Timestamp date2timestamp(Date date) {

        if(Objects.isNull(date)){
            return null;
        }

        return new Timestamp(date.getTime());

    }
}
